﻿/**********************************************
* 作    者：YuBing
* 创建日期：2009年02月20日
* 描    述：封装IBatisNet底层操作
* 修改日期：2009年07月06日
***********************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using Meqs.Logic.Batcher;

namespace Meqs.Logic
{
    using IBatisNet.Common;
    using IBatisNet.Common.Pagination;
    using IBatisNet.DataMapper;
    using IBatisNet.DataMapper.Commands;
    using IBatisNet.DataMapper.Configuration.Statements;
    using IBatisNet.DataMapper.Exceptions;
    using IBatisNet.DataMapper.MappedStatements;
    using IBatisNet.DataMapper.Scope;

    /// <summary>
    /// BaseSqlMapDao
    /// 封装IBatisNet底层操作
    /// 
    /// 修改记录:
    ///     2009-04-20 10:00 代码创建
    ///     2009-07-06 10:32 新增对自定义读取配置文件节点，并操作
    ///     2009-07-06 15:57 新增批处理方法，支持批量新增、修改、删除 
    ///     2009-07-15 14:04 sqlMap变量修改为私有及只读
    ///     2009-07-16 09:13 开放对连接字符串的访问,ConnectionString
    /// <author>
    ///     <name>YuBing</name>
    ///     <date>2009/07/07</date>
    /// </author>
    /// </summary>
    /// <remarks>
    /// 所有可供调用的方法均为protected，防止外部程序调用
    /// 只有继承该类方能调用
    /// </remarks>
    public abstract class BaseSqlMapDao
    {
        #region private static readonly ISqlMapper sqlMap

        /// <summary>
        /// ISqlMapper实例
        /// 从WindsorContainer容器中获取
        /// </summary>
        /// <returns></returns>
        private static readonly ISqlMapper sqlMap = (ContainerAccessorUtil.GetContainer())["sqlServerSqlMap"] as ISqlMapper;

        #endregion

        #region public virtual IList<T> ExecuteQueryForList<T>(string statementName, object parameterObject)

        /// <summary>
        /// 获取列表
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="statementName">操作名称，对应xml中的Statement的id</param>
        /// <param name="parameterObject">参数</param>
        /// <returns></returns>
        public virtual IList<T> ExecuteQueryForList<T>(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.QueryForList<T>(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for list.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region public virtual IList ExecuteQueryForList(string statementName, object parameterObject)

        /// <summary>
        /// 获取列表
        /// </summary>
        /// <param name="statementName">操作名称，对应xml中的Statement的id</param>
        /// <param name="parameterObject">参数</param>
        /// <returns></returns>
        public virtual IList ExecuteQueryForList(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.QueryForList(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for list.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region public virtual IList<T> ExecuteQueryForList<T>(string statementName, object parameterObject, int skipResults, int maxResults)

        /// <summary>
        /// 得到指定数量的记录数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="statementName"></param>
        /// <param name="parameterObject">参数</param>
        /// <param name="skipResults">跳过的记录数</param>
        /// <param name="maxResults">最大返回的记录数</param>
        /// <returns></returns>
        public virtual IList<T> ExecuteQueryForList<T>(string statementName, object parameterObject, int skipResults, int maxResults)
        {
            try
            {

                return sqlMap.QueryForList<T>(statementName, parameterObject, skipResults, maxResults);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for list.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region protected virtual IPaginatedList ExecuteQueryForPaginatedList(string statementName, object parameterObject, int pageSize)

        /// <summary>
        /// 获取分页的列表
        /// </summary>
        /// <param name="statementName">操作名称</param>
        /// <param name="parameterObject">参数</param>
        /// <param name="pageSize">每页记录数</param>
        /// <returns></returns>
        protected virtual IPaginatedList ExecuteQueryForPaginatedList(string statementName, object parameterObject, int pageSize)
        {
            try
            {
                return sqlMap.QueryForPaginatedList(statementName, parameterObject, pageSize);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for paginated list.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region protected virtual T ExecuteQueryForObject<T>(string statementName, object parameterObject)

        /// <summary>
        /// 查询得到对象的一个实例
        /// </summary>
        /// <typeparam name="T">对象type</typeparam>
        /// <param name="statementName">操作名</param>
        /// <param name="parameterObject">参数</param>
        /// <returns></returns>
        protected virtual T ExecuteQueryForObject<T>(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.QueryForObject<T>(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for object.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region protected virtual object ExecuteQueryForObject(string statementName, object parameterObject)

        /// <summary>
        /// 查询得到对象的一个实例
        /// </summary>
        /// <param name="statementName">操作名</param>
        /// <param name="parameterObject">参数</param>
        /// <returns></returns>
        protected virtual object ExecuteQueryForObject(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.QueryForObject(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for object.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region protected virtual object ExecuteInsert(string statementName, object parameterObject)

        /// <summary>
        /// 执行添加
        /// </summary>
        /// <param name="statementName">操作名</param>
        /// <param name="parameterObject">参数</param>
        protected virtual object ExecuteInsert(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.Insert(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for insert.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region protected virtual int ExecuteUpdate(string statementName, object parameterObject)

        /// <summary>
        /// 执行修改
        /// </summary>
        /// <param name="statementName">操作名</param>
        /// <param name="parameterObject">参数</param>
        protected virtual int ExecuteUpdate(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.Update(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for update.  Cause: " + e.Message, e);
            }
        }

        #endregion

        #region protected virtual int ExecuteDelete(string statementName, object parameterObject)

        /// <summary>
        /// 执行删除
        /// </summary>
        /// <param name="statementName">操作名</param>
        /// <param name="parameterObject">参数</param>
        protected virtual int ExecuteDelete(string statementName, object parameterObject)
        {
            try
            {
                return sqlMap.Delete(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new DataMapperException("Error executing query '" + statementName + "' for delete.  Cause: " + e.Message, e);
            }
        }

        #endregion


        #region AdoNet操作

		/// <summary>
        /// 返回一个DataTable
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="parameterObject"></param>
        /// <returns></returns>
        public DataTable QueryForDataTable(string statementName, Hashtable parameterObject)
        {
            DataTable dt = new DataTable();
            string connStr = sqlMap.DataSource.ConnectionString;
            using (SqlConnection conn = new SqlConnection(connStr))
            {
                conn.Open();
            }
            return dt;
        }

		/// <summary>
        /// 返回IDbCommand的函数
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="parameterObject"></param>
        /// <returns></returns>
        private IDbCommand GetDbCommand(string statementName, object parameterObject)
        {
            IDbCommand p_command;
            IDalSession m_sqlSession;

            if (sqlMap.LocalSession != null)
            {
                m_sqlSession = sqlMap.LocalSession;
            }
            else
            {
                m_sqlSession = sqlMap.OpenConnection();
            }
            IMappedStatement mappedStatement = sqlMap.GetMappedStatement(statementName);
            RequestScope requestScope = mappedStatement.Statement.Sql.GetRequestScope(mappedStatement, parameterObject, m_sqlSession);
            // 通过这个方法生成一个DbCommand，并且给所有的SQL参数指定值。如果没有调用此方法，requestScope.IDbCommand属性为空  //
            mappedStatement.PreparedCommand.Create(requestScope,
             m_sqlSession, mappedStatement.Statement, parameterObject);
            p_command = requestScope.IDbCommand;
            return p_command;
        }
		
		/// <summary>
        /// 实现返回DataSet的函数
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="parameterObject"></param>
        /// <returns></returns>
        protected DataSet ExecuteQueryTable(string statementName, object parameterObject)
        {
            DataSet ds = new DataSet();
            IDbCommand cmd = GetDbCommand(statementName, parameterObject);
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = GetSql(statementName, parameterObject);
            if (sqlMap.LocalSession != null)
            {
                IDbDataAdapter adapter =
                 sqlMap.LocalSession.CreateDataAdapter(cmd);
                adapter.Fill(ds);
                return ds;
            }
            else
            {
                IDalSession session = sqlMap.OpenConnection();
                IDbDataAdapter adapter =
                 session.CreateDataAdapter(cmd);
                adapter.Fill(ds);
                session.CloseConnection();
                return ds;
            }
        }
		
		/// <summary>
        /// 结果集返回一个DataSet
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="parameterObject"></param>
        /// <returns></returns>
        protected virtual DataSet QueryForDataSet(string statementName, object parameterObject)
        {
            DataSet ds = new DataSet();
            IMappedStatement statement = sqlMap.GetMappedStatement(statementName);
            if (!sqlMap.IsSessionStarted)
            {
                sqlMap.OpenConnection();
            }
            RequestScope scope = statement.Statement.Sql.GetRequestScope(statement, parameterObject, sqlMap.LocalSession);
            statement.PreparedCommand.Create(scope, sqlMap.LocalSession, statement.Statement, parameterObject);
            sqlMap.LocalSession.CreateDataAdapter(scope.IDbCommand).Fill(ds);

            return ds;
        }
		
        /// <summary>
        /// 获取xml文件配置块的sql语句
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="parameterObject"></param>
        /// <returns></returns>
        protected virtual string GetSql(string statementName, object parameterObject)
        {
            IMappedStatement statement = sqlMap.GetMappedStatement(statementName);
            if (!sqlMap.IsSessionStarted)
            {
                sqlMap.OpenConnection();
            }
            RequestScope scope = statement.Statement.Sql.GetRequestScope(statement, parameterObject, sqlMap.LocalSession);

            return scope.PreparedStatement.PreparedSql;
        }
        #endregion

        #region 批处理

        #region protected virtual int BatchSave<T>(string statementName, IList<T> objArray)

        /// <summary>
        /// 批量保存
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="objArray"></param>
        /// <returns></returns>
        protected virtual int BatchSave<T>(string statementName, IList<T> objArray)
        {
            return Batch(statementName, "INSERT", objArray);
        }

        #endregion

        #region protected virtual int BatchUpdate<T>(string statementName, IList<T> objArray)

        /// <summary>
        /// 批量更新
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="objArray"></param>
        /// <returns></returns>
        protected virtual int BatchUpdate<T>(string statementName, IList<T> objArray)
        {
            return Batch(statementName, "UPDATE", objArray);
        }

        #endregion

        #region protected virtual int BatchDelete<T>(string statementName, IList<T> objArray)

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="statementName"></param>
        /// <param name="objArray"></param>
        /// <returns></returns>
        protected virtual int BatchDelete<T>(string statementName, IList<T> objArray)
        {
            return Batch(statementName, "DELETE", objArray);
        }

        #endregion

        // 批处理私有方法
        #region private int Batch<T>(string statementName, string type, IList<T> objArray)

        /// <summary>
        /// 批处理
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="statementName"></param>
        /// <param name="type"></param>
        /// <param name="objArray"></param>
        /// <returns></returns>
        private int Batch<T>(string statementName, string type, IList<T> objArray)
        {
            if (statementName == null)
                throw new ArgumentNullException("statementName");
            if (objArray == null)
                throw new ArgumentNullException("objArray");
            if (objArray.Count < 1)
                throw new ArgumentException("objArray");

            SqlBatcher m_Batcher = new SqlBatcher();
            IDalSession session = new SqlMapSession(sqlMap);
            IMappedStatement mappedStatment = sqlMap.GetMappedStatement(statementName);
            IStatement st = mappedStatment.Statement;
            IPreparedCommand pc = mappedStatment.PreparedCommand;

            // 执行批处理命令
            System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(session.DataSource.ConnectionString);
            conn.Open();
            System.Data.SqlClient.SqlTransaction tran = conn.BeginTransaction();
            m_Batcher.StartBatch(conn, tran, type);
            RequestScope request = st.Sql.GetRequestScope(mappedStatment, objArray[0], session);
            
            foreach (T app in objArray)
            {
                pc.Create(request, session, st, app);

                // 转化 IBatis 包装后的 DbCommand 为 原始的 DbCommand
                mappedStatment.PreparedCommand.Create(request, session, st, app);
                IDbCommand command = request.IDbCommand;
                command.Transaction = tran;
                m_Batcher.AddToBatch(command);
            }
            session.OpenConnection();
            int ret;
            try
            {
                ret = m_Batcher.ExecuteBatch();
                m_Batcher.EndBatch();
                tran.Commit();
            }
            catch (Exception)
            {
                tran.Rollback();
                ret = 0;
            }
            conn.Close();
            return ret;
        }
        #endregion

        #region protected int SqlBatchInsert(SqlConnection conn, IList<SqlCommand> cmdList)

        /// <summary>
        /// ADO.NET批插入
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="cmdList"></param>
        /// <returns></returns>
        protected int SqlBatchInsert(SqlConnection conn, IList<SqlCommand> cmdList)
        {
            return SqlBatchInsert(conn, cmdList, null);
        }

        #endregion

        #region protected int SqlBatchInsert(SqlConnection conn, IList<SqlCommand> cmdList, SqlTransaction tran)

        /// <summary>
        /// ADO.NET批插入
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="cmdList"></param>
        /// <param name="tran"></param>
        /// <returns></returns>
        protected int SqlBatchInsert(SqlConnection conn, IList<SqlCommand> cmdList, SqlTransaction tran)
        {
            bool flag = tran == null;
            SqlBatcher m_Batcher = new SqlBatcher();
            if (flag) tran = conn.BeginTransaction();
            m_Batcher.StartBatch(conn, tran, "INSERT");
            foreach (SqlCommand command in cmdList)
            {
                command.Transaction = tran;
                m_Batcher.AddToBatch(command);
            }
            int ret;
            try
            {
                ret = m_Batcher.ExecuteBatch();
                m_Batcher.EndBatch();
                if (flag) tran.Commit();
            }
            catch (Exception)
            {
                if (flag) tran.Rollback();
                ret = 0;
            }
            return ret;
        }

        #endregion

        #endregion

        #region protected static string ConnectionString

        /// <summary>
        /// 获取当前的连接字符串
        /// </summary>
        protected static string ConnectionString
        {
            get
            {
                return sqlMap.DataSource.ConnectionString;
            }
        }

        #endregion

        #region protected static string ConnectionString

        /// <summary>
        /// 获取当前的连接字符串
        /// </summary>
        protected static ISqlMapper SqlMap
        {
            get
            {
                return sqlMap;
            }
        }

        #endregion
    }
}